Destructuring and spread syntax consume iterables by calling Symbol.iterator and pulling values until done, allowing them to work with any custom iterable.
When you write [a, b, ...rest] = iterable, JavaScript calls iterable[Symbol.iterator]() and reads values until the pattern is satisfied. Similarly, [...iterable] collects all values. This is why you can use spread on Set, Map (with caution), String, and custom iterables.